package liuyang.bigeventserver.modules.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import liuyang.bigeventserver.common.CacheService;
import liuyang.bigeventserver.common.R;
import liuyang.bigeventserver.modules.security.jwt.JwtTokenService;
import liuyang.bigeventserver.modules.security.vo.CachedInfo;
import liuyang.bigeventserver.modules.security.vo.SysUserDetails;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 认证成功后
 * 1. 签发JWT
 * 2. 把用户信息存到缓存中（Redis）
 * 3. 向前端返回JWT和鉴权信息
 *
 * 视频：
 * https://www.bilibili.com/video/BV1Fd4y1k7rq/?p=39&spm_id_from=pageDriver&vd_source=8bd7b24b38e3e12c558d839b352b32f4
 * 用户认证信息:
 * https://www.bilibili.com/video/BV14b4y1A7Wz/?p=29&spm_id_from=pageDriver&vd_source=8bd7b24b38e3e12c558d839b352b32f4
 * SecurityContextHolder
 *  SecurityContext
 *      Authentication
 *          - Principal
 *          - Credentials
 *          - Authorities
 *
 * 说明：
 * 配合UsernamePasswordAuthenticationFilter使用
 * 也可以给默认登录页面用http.formLogin().successHandler(restAuthenticationSuccessHandler);
 *
 * @author liuyang
 * @since 2022/1/25
 *        2024/2/27 更换为jakarta包，并组件化@Component
 *        2024/2/28 增加签发JWT内容
 *        2024/2
 */
@Component
@Slf4j
@AllArgsConstructor
public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final ObjectMapper om;
    private final JwtTokenService jwtTokenService;
    private final CacheService cacheService;
    private final RedisTemplate<String, Object> redisTemplate3;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //ObjectMapper om = new ObjectMapper();

        // 签发JWT
        //org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User)authentication.getPrincipal();
        SysUserDetails user = (SysUserDetails)authentication.getPrincipal();// SysUserDetails里包含了用户id
        String jwt = jwtTokenService.sign(String.valueOf(user.getUserid()), user.getUsername());// 把id也放入jwt中方便后续业务逻辑中使用
        // 把JWT保存在缓存中
        //redisTemplate3.opsForValue().set(user.getUsername(), authentication);
        CachedInfo cachedInfo = new CachedInfo(jwt, user.getAuthorities());
        redisTemplate3.opsForValue().set(user.getUsername(), cachedInfo);
        // 返回信息
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Cache-Control", "no-cache");
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");

        // need JDK 11
        /*Map<String, Object> msg = Map.of(
                "msg", "认证成功",
                "token", authentication);*/
        response.getWriter().println(om.writeValueAsString(R.ok("认证成功").put("token", jwt)
                // 这个仅开发的时候用，比较方便
                .put("authentication", authentication)));

        // 调试
        log.debug("认证成功");
        log.debug("authentication = {}", authentication);// 观察控制台，可以看出里面的结构。
    }
}
